home *** CD-ROM | disk | FTP | other *** search
/ Interactive Web Graphics with Shout 3D / Interactive Web Graphics With Shout 3D.iso / mac / Shout3Ddemo / Shout3d_runtime / codebase / applets / MultiTestPanel.java < prev    next >
Text File  |  2000-10-10  |  13KB  |  388 lines

  1. /**    
  2.     Company:        Eyematic Interfaces
  3.     Project:        Shout3D 2.0 Sample Code
  4.     Class:            MultiTestPanel
  5.     Date:            April 26, 1999
  6.     Description:    Tests various features. Press '?' for Java Panel instructions
  7.     (C) Copyright Eyematic Interfaces, Inc. - 1997-2000 - All rights reserved
  8.  */
  9.  
  10. package applets;
  11.  
  12. import java.applet.*;
  13. import java.awt.*;
  14. import java.awt.image.*;
  15. import java.io.*;
  16. import java.util.Date;
  17. import java.util.Vector;
  18. import java.net.URL;
  19. import shout3d.*;
  20. import shout3d.math.*;
  21. import shout3d.core.*;
  22.  
  23. /**
  24.  * 
  25.  * Panel that tests lots of features, including 
  26.  * little markers that show the location and normal of geometry
  27.  * below the mouse.
  28.  * 
  29.  *  Press '?' to see instructions in the Java Panel.
  30.  * 
  31.  * @author Paul Isaacs
  32.  * @author Jim Stewartson
  33.  * @author Dave Westwood
  34.  */
  35.  
  36. public class MultiTestPanel extends Shout3DPanel implements DeviceObserver {
  37.     boolean   locationTracking = false;
  38.     boolean   normalTracking = false;
  39.     int          curMouseX, curMouseY;
  40.     boolean   mouseMoved = false;
  41.  
  42.     /**
  43.      * Constructor
  44.      */
  45.     public MultiTestPanel(Shout3DApplet applet){
  46.         super(applet);
  47.     }
  48.     
  49.     public void customInitialize(){
  50.         // Register to watch rendering, the keyboard and mouse
  51.         addDeviceObserver(this,"KeyboardInput", null);
  52.         addDeviceObserver(this,"MouseInput", null);
  53.         getRenderer().addRenderObserver(this,null);
  54.  
  55.         String normalTrackingString   = applet.getParameter("normalTracking");
  56.         if (normalTrackingString != null && normalTrackingString.equals("true"))
  57.             normalTracking = true;
  58.         else
  59.             normalTracking = false;
  60.  
  61.         String locationTrackingString = applet.getParameter("locationTracking");
  62.         if (locationTrackingString != null && locationTrackingString.equals("true"))
  63.             locationTracking = true;
  64.         else
  65.             locationTracking = false;
  66.  
  67.     }
  68.         
  69.     /**
  70.      *  Clean up by unregistering observers
  71.      */
  72.     protected void finalize() throws Throwable { 
  73.         getRenderer().removeRenderObserver(this);
  74.         removeDeviceObserver(this,"KeyboardInput");
  75.         removeDeviceObserver(this,"MouseInput");
  76.         super.finalize();
  77.     }
  78.     
  79.     /**
  80.      *  Override to do a pick and show results, if desired.
  81.      * Tracking of the pick must be performed during onPostRender.
  82.      * This is because multithreading may put rendering in a separate thread,
  83.      * but  trackPick() adds/removes children.
  84.      * Hence, unless we insure that trackPick() occurs between renders, 
  85.      * the children could disappear during the middle
  86.      * of a render, which can cause null pointer exceptions.
  87.      * 
  88.      * Note that no onPreRender() method is implemented in this class,
  89.      * even though it is required for all classes implementing RenderObserver.
  90.      * This is because the super class implements RenderObserver fully 
  91.      * and onPreRender is inherited.  
  92.      * Hence this class needs only to override the onPostRender() method, 
  93.      * making sure to call super.onPostRender(r,userData) within the body 
  94.      * of the method.
  95.      */
  96.     public void onPostRender(Renderer r, Object userData) {
  97.         super.onPostRender(r,userData);
  98.         if (mouseMoved &&  (locationTracking || normalTracking))
  99.             trackPick();
  100.     }
  101.     
  102.     //{{ DeviceObserver methods
  103.     /**
  104.      * Processes mouse and keyboard input.
  105.      * 
  106.      * Moving the mouse records the mouse location for later use during
  107.      * trackPick(), which is called between renders (see onPostRender above)
  108.      * 
  109.      * Pressing keyboard keys performs any of a series of tests.
  110.      * 
  111.      */
  112.     public boolean onDeviceInput(DeviceInput di, Object userData) {
  113.         if (di instanceof MouseInput){
  114.             if (((MouseInput)di).which == MouseInput.MOVE) {
  115.                 curMouseX = ((MouseInput)di).x;
  116.                 curMouseY = ((MouseInput)di).y;
  117.                 // Do not do the pick right here.  Set this flag so it will
  118.                 // occur during onPostRender. See onPostRender for why.
  119.                 mouseMoved = true;
  120.             }
  121.         }
  122.         else {
  123.             KeyboardInput ki = (KeyboardInput) di;
  124.             if (ki.which == KeyboardInput.PRESS) {
  125.                 switch(ki.key) {
  126.                 case 'w': case 'W':
  127.                     // W key pressed. Write the scene to a little text frame
  128.                     // (WriterTextFrame is defined in this file.
  129.                     if (getScene() != null) {
  130.                         WriterTextFrame myFrame = new WriterTextFrame();
  131.                         myFrame.resize(400, 600);
  132.                         myFrame.show();
  133.  
  134.                         ByteArrayOutputStream os = new ByteArrayOutputStream();
  135.                         PrintStream ps = new PrintStream(os);
  136.                         Shout3DWriter writer = new Shout3DWriter();
  137.                         writer.write(getScene(),ps);
  138.                         myFrame.getTextArea().setText(os.toString());
  139.                     }
  140.                     return true;
  141.                 case 'n': case 'N':
  142.                     // N key pressed. Toggle normal-tracking. Each time the mouse moves, do a 
  143.                     // pick and place arrow at picked location, pointing in direction of normal
  144.                     // info to the console. 
  145.                     normalTracking = !normalTracking;
  146.                     if (!normalTracking)
  147.                         hideNormalMarker();
  148.                     break;
  149.                 case 'l': case 'L':
  150.                     // L key pressed. Toggle location tracking. Each time the mouse moves, do a pick 
  151.                     // and place nubbin at picked location.
  152.                     locationTracking = !locationTracking;
  153.                     if (!locationTracking)
  154.                         hidePositionMarker();
  155.                     break;
  156.                 case '1':
  157.                     //  prints paths to all IndexedFaceSet nodes.
  158.                     searchAndPrint("IndexedFaceSet");
  159.                     break;
  160.                 case '2':
  161.                     //  prints paths to all TimeSensor nodes.
  162.                     searchAndPrint("TimeSensor");
  163.                     break;
  164.                 case '3':
  165.                     //  prints paths to all Group nodes.
  166.                     searchAndPrint("Group");
  167.                     break;
  168.                 case '4':
  169.                     //  prints paths to all nodes.
  170.                     searchAndPrint("Node");
  171.                     break;
  172.                 case '5':
  173.                     //  prints paths to all nodes.
  174.                     searchAndPrint("Switch");
  175.                     break;
  176.                 case '?':
  177.                     // Print help message.
  178.                     System.out.println("-----------------------------------");
  179.                     System.out.println("KEY:    ACTION:");
  180.                     System.out.println("n       NORMAL picking toggle.  Turns tracking of surface normal on/off");
  181.                     System.out.println("l       LOCATION picking toggle.  Turns tracking of picked location on/off");
  182.                     System.out.println("w       WRITE scene to textArea in VRML-like syntax");
  183.                     System.out.println("1       #1--diagnostic - search for IndexedFaceSets");
  184.                     System.out.println("            and print paths to them");
  185.                     System.out.println("2       #2--diagnostic - search for TimeSensors");
  186.                     System.out.println("            and print paths to them");
  187.                     System.out.println("3       #3--diagnostic - search for Groups");
  188.                     System.out.println("            and print paths to them");
  189.                     System.out.println("4       #4--diagnostic - search for all Nodes");
  190.                     System.out.println("            and print paths to them");
  191.                 }
  192.             }
  193.         }
  194.         return false;
  195.     }
  196.     //}} DeviceObserver methods
  197.     
  198.     /**
  199.      * Searches for paths to all nodes of the given type, printing the results
  200.      * to the console.
  201.      */
  202.     void searchAndPrint(String typeName) {
  203.         System.out.println("RESULTS OF SEARCH FOR ALL " + typeName + "s :");
  204.         Searcher s = getNewSearcher();
  205.         s.setType(typeName);
  206.         Node[][] paths = s.searchAll(getScene());
  207.         if (paths == null || paths.length == 0) {
  208.             System.out.println("No paths found");
  209.             return;
  210.         }
  211.         System.out.println("Number of paths is " + paths.length);
  212.         for (int i = 0; i < paths.length; i++) {
  213.             Node[] p = paths[i];
  214.             System.out.println("PATH " + i);
  215.             for (int j = 0; j < p.length; j++) {
  216.                 if (p[j] == null) 
  217.                     System.out.println("   node " + j + " is null");
  218.                 else {
  219.                     String name = p[j].getDEFName();
  220.                     if (name == null)
  221.                         name = "";
  222.                     System.out.println("   node " + j + " name:" + name + " type " + p[j].getTypeName());
  223.                 }
  224.             }
  225.         }
  226.         System.out.println("-------------------------------------------");
  227.     }
  228.  
  229.     Picker myPicker;    
  230.     private Node[] pickPath;
  231.     /**
  232.      * Tracks the current cursor location with a nubbin or an arrow.
  233.      * 
  234.      * If normalTracking, then an arrow will be stuck at the picked
  235.      * location, pointing in the direction of the pick-point-normal.
  236.      * 
  237.      * If locationTracking, then a nubbin will be placed at the picked location.
  238.      */
  239.     void trackPick() {
  240.         if (myPicker == null)
  241.             myPicker = getNewPicker();
  242.         myPicker.setPickInfo(Picker.POINT, (normalTracking || locationTracking));//Only needed for these two
  243.         myPicker.setPickInfo(Picker.NORMAL, normalTracking);//Only if normalTracking
  244.         // Hide the markers, so that the markers can't be picked.
  245.         hideNormalMarker();
  246.         hidePositionMarker();
  247.         pickPath = myPicker.pickClosest(curMouseX, curMouseY);
  248.         float[] pickedPoint = myPicker.getPickInfo(Picker.POINT);//Garbage if (!normalTracking&&!locationTracking)
  249.         float[] pickedNormal = myPicker.getPickInfo(Picker.NORMAL);//Garbage if !normalTracking
  250.         if (pickPath != null){
  251.             if (locationTracking)
  252.                 showPositionMarker(pickedPoint);
  253.             if (normalTracking)
  254.                 showNormalMarker(pickedPoint, pickedNormal);
  255.         }
  256.         mouseMoved = false;
  257.     }
  258.     
  259.     // These store references to the markers
  260.     Transform positionMarker, normalMarker;
  261.     // These are cached to easily call addChidren/removeChildren
  262.     Node[]    positionMarkerKidArray;
  263.     Node[]    normalMarkerKidArray;
  264.     // Scale applied to the marker,
  265.     // can be set with the markerScale parameter in the html file.
  266.     float[] markerScale = { .1f, .1f, .1f};
  267.     
  268.     /**
  269.      * Hides the normal marker by removing from the scene.
  270.      */
  271.     void hideNormalMarker(){
  272.         if (normalMarker != null) {
  273.             getScene().removeChildren(normalMarkerKidArray);
  274.         }
  275.     }
  276.     /**
  277.      * Hides the position marker by removing from the scene.
  278.      */
  279.     void hidePositionMarker(){
  280.         if (positionMarker != null){
  281.             getScene().removeChildren(positionMarkerKidArray);
  282.         }
  283.     }
  284.     /**
  285.      * Shows the normal marker and places according to input parameters.
  286.      */
  287.     void showNormalMarker(float[/*3*/]position, float[/*3*/] direction){
  288.         if (normalMarker == null){
  289.             initMarkerGeoms();
  290.         }
  291.         normalMarker.translation.setValue(position);
  292.         //Set rotation to point the y axis towards the direction. Axis is cross product, angle is acos(dotProduct)
  293.         // Axis is cross product yAxis.cross(direction), which is (dz, 0, -dx)
  294.         normalMarker.rotation.getValue()[0] = direction[2];
  295.         normalMarker.rotation.getValue()[1] = 0;
  296.         normalMarker.rotation.getValue()[2] = -direction[0];
  297.         MatUtil.normalize(normalMarker.rotation.getValue()); // will just normalize 1st 3 of 4 components
  298.         normalMarker.rotation.getValue()[3] = (float) Math.acos(direction[1]); // angle whose cosine is dotprod of (0,1,0) and direction
  299.         normalMarker.rotation.setValue(normalMarker.rotation.getValue());
  300.         getScene().addChildren(normalMarkerKidArray);
  301.     }
  302.     /**
  303.      * Shows the position marker and places according to input parameters.
  304.      */
  305.     void showPositionMarker(float[/*3*/]position){
  306.         if (positionMarker == null){
  307.             initMarkerGeoms();
  308.         }
  309.         positionMarker.translation.setValue(position);
  310.         getScene().addChildren(positionMarkerKidArray);
  311.     }        
  312.     
  313.     /**
  314.      * Reads the file given by the parameter "markerGeometry"
  315.      * and searches inside for two named nodes:
  316.      * "PositionMarker" and "NormalMarker"
  317.      * 
  318.      * Saves these and also scales them by markerScale (which
  319.      * may be set as an html input parameter)
  320.      */
  321.     void initMarkerGeoms(){
  322.         Transform markerRoot = new Transform();
  323.         String markerGeomString = applet.getParameter("markerGeometry");
  324.         if (markerGeomString == null){
  325.             System.out.println("Error -- Mo markerGeometry parameter specified for applet");
  326.             System.out.println("         Can not show picked location");
  327.             return;
  328.         }
  329.         String[] urlArray = { markerGeomString };
  330.         // Don't load in a separate thread:
  331.         boolean wasSeparate = isLoadResourcesInSeparateThread();
  332.         setLoadResourcesInSeparateThread(false);
  333.         loadURL(urlArray, markerRoot);
  334.         setLoadResourcesInSeparateThread(wasSeparate);
  335.         if (markerRoot == null) {
  336.             throw new Shout3DException("ERROR - could not load marker geometry");
  337.         }
  338.         Searcher mySearcher = getNewSearcher();
  339.         
  340.         // initialize positionMarker
  341.         mySearcher.setDefName("PositionMarker");
  342.         Node[] sResult = mySearcher.searchFirst(markerRoot);
  343.         if (sResult==null){
  344.             throw new Shout3DException("ERROR - could not find PositionMarker");
  345.         }
  346.         positionMarker = (Transform) sResult[sResult.length-1];
  347.         // Create the array used to add the positionMarker to the scene.
  348.         positionMarkerKidArray = new Node[1];
  349.         positionMarkerKidArray[0] = positionMarker;
  350.         
  351.         // initialize normalMarker
  352.         mySearcher.setDefName("NormalMarker");
  353.         sResult = mySearcher.searchFirst(markerRoot);
  354.         if (sResult==null){
  355.             throw new Shout3DException("ERROR - could not find NormalMarker");
  356.         }
  357.         normalMarker = (Transform) sResult[sResult.length-1];
  358.         // Create the array used to add the normalMarker to the scene.
  359.         normalMarkerKidArray = new Node[1];
  360.         normalMarkerKidArray[0] = normalMarker;
  361.  
  362.         String markerScaleParamString = applet.getParameter("markerScale");
  363.         if (markerScaleParamString != null){
  364.             markerScale[0] = markerScale[1] = markerScale[2] = Float.valueOf(markerScaleParamString).floatValue();
  365.         }
  366.  
  367.         positionMarker.scale.setValue(markerScale);
  368.         normalMarker.scale.setValue(markerScale);
  369.         
  370.     }
  371.         
  372. }
  373.  
  374. /**
  375.  * A little class that puts a text area in its own 
  376.  * free floating frame.
  377.  */
  378. class WriterTextFrame extends Frame {
  379.     TextArea myTextArea;
  380.     WriterTextFrame() {
  381.         setLayout(new BorderLayout());
  382.         myTextArea = new TextArea();
  383.         this.add("Center",myTextArea);
  384.     }
  385.     
  386.     TextArea  getTextArea() { return myTextArea; }
  387. }
  388.